#include <regex>

#include "mpFishMapper.h"
//https://www.cnblogs.com/Stephen-Qin/p/10157081.html
//http://www.cochoy.fr/boost-property-tree/

//boost json put int，double保存为string而不能保存int，double的解决方法
//https://www.cnblogs.com/rayfloyd/p/14330051.html
//https://blog.csdn.net/byxdaz/article/details/82261018
//https://stackoverflow.com/questions/2855741/why-does-boost-property-tree-write-json-save-everything-as-string-is-it-possibl

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/optional/optional.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>

#include "mpCodecUtils.h"
#include "mpLog.h"

namespace pt = boost::property_tree;

namespace MP{
namespace Mapper{

//private member
namespace{

void checkServerSideError(pt::ptree& pt,
                          ServerSideErrorInfo& err) {

    //检查是否有服务端异常返回
    boost::optional<pt::ptree&> tempNode = pt.get_child_optional("Error");
    if(tempNode)
    {
        tempNode =  pt.get_child_optional("Error.No");
        if (tempNode)
        {
            err.No = (*tempNode).get_value<std::string>();
        }

        tempNode =  pt.get_child_optional("Error.Message");
        if (tempNode)
        {
            err.Message = (*tempNode).get_value<std::string>();
        }
    }
    else{

        //检查是否授权异常
        int auth_code = 0;
        tempNode = pt.get_child_optional("auth_code");
        if(tempNode){
            auth_code = (*tempNode).get_value<int>();
        }

        if(auth_code != 0){
            err.No = std::to_string(auth_code);

            tempNode =  pt.get_child_optional("auth_message");
            if (tempNode)
            {
                err.Message = (*tempNode).get_value<std::string>();
            }
        }
    }
}

std::string get_stringValue(boost::optional<pt::ptree&>& node){
    std::string strValue = (*node).get_value<std::string>();
    if (boost::iequals(strValue, "null")) {
        strValue = "";
    }
    return strValue;
}

template <class T>
bool get_jsonValue(boost::property_tree::ptree &pt, T &value, const std::string &sect)
{
    try {
        value = pt.get<T>(sect);
    } catch (boost::property_tree::ptree_bad_path&){
        return false;
    }
    return true;
}


//由于BOOST property_tree在生成json的时候会将int double long bool值添加双引号，这种做法不符合JSON标准格式
//因此此处做一下标准化处理
void standardizedOutput(pt::ptree& tree,
                        std::string & json,
                        bool hasNumber,
                        bool hasBoolean){

    std::ostringstream data;
    pt::write_json(data, tree, false);

    if(hasNumber){
        std::regex reg("\\\"([0-9]+\\.{0,1}[0-9]*)\\\"");
        json = std::regex_replace(data.str(), reg, "$1");
    }
    else{
        json = data.str();
    }

    if(hasBoolean){
        boost::replace_all<std::string>(json, "\"true\"", "true");
        boost::replace_all<std::string>(json, "\"false\"", "false");
    }
}



void assignmentToFishInfo(pt::ptree& tree,
                          FishInfo& fish){

    boost::optional<pt::ptree&> tempNode = tree.get_child_optional("Id");
    if (tempNode){
        fish.Id = (*tempNode).get_value<long>();
    }

    tempNode = tree.get_child_optional("Name");
    if (tempNode){
        fish.Name = get_stringValue(tempNode);
    }

    tempNode = tree.get_child_optional("Pinyin");
    if (tempNode){
        fish.Pinyin = get_stringValue(tempNode);
    }

    tempNode = tree.get_child_optional("Describe");
    if (tempNode){
        fish.Describe = get_stringValue(tempNode);
    }

    tempNode = tree.get_child_optional("IsLivingInSea");
    if (tempNode){
        fish.IsLivingInSea = (*tempNode).get_value<bool>();
    }
}

} //private member

void jsonStringMapperToObject(std::stringstream & stream,
                              FishInfo& fish,
                              ServerSideErrorInfo& err){

    try
    {
        if(stream.rdbuf()->in_avail() != 0){
            //按照utf8的格式加载xml文件
            pt::ptree tree;

            pt::read_json(stream, tree);

            checkServerSideError(tree,err);

            if(!err.ServerSideHasError()){
                assignmentToFishInfo(tree,fish);
            }
        }


    }
    catch (const std::exception& e)
    {
        MPLOG_ERROR << "jsonStringMapperToObject error. " << e.what();
    }
    catch (...)
    {
        MPLOG_ERROR << "jsonStringMapperToObject error";
    }


//    if(stream.rdbuf()->in_avail() != 0){


//    }
}

void jsonStringMapperToObjectList(std::stringstream& stream,
                                  std::vector<FishInfo>& fishs,
                                  ServerSideErrorInfo& err){

    try
    {
        if(stream.rdbuf()->in_avail() != 0){
            //按照utf8的格式加载
            pt::ptree tree;
            pt::read_json(stream, tree);

            checkServerSideError(tree,err);

            if(!err.ServerSideHasError()){

                BOOST_FOREACH(pt::ptree::value_type& v1, tree){
                    FishInfo item;
                    assignmentToFishInfo(v1.second,item);
                    fishs.push_back(item);
                }
            }
        }


    }
    catch (const std::exception& e)
    {
        MPLOG_ERROR << "jsonStringMapperToObjectList error. " << e.what();
    }
    catch (...)
    {
        MPLOG_ERROR << "jsonStringMapperToObjectList error";
    }


}


void objectMapperToJsonString(const FishInfo& fish,
                              std::string & string){

    //按照utf8的格式加载
    pt::ptree tree;

    tree.put<long>("Id",fish.Id);
    tree.put<std::string>("Name",fish.Name);
    tree.put<std::string>("Pinyin",fish.Pinyin);
    tree.put<std::string>("Describe",fish.Describe);
    tree.put<bool>("IsLivingInSea",fish.IsLivingInSea);

    standardizedOutput(tree,string,true,true);
//    std::ostringstream data;
//    pt::write_json(data, tree, false);

//    string = data.str();

//    pt::ptree tmpeNode;
//    for (unsigned int i = 0; i < formOptionsInfos.size(); i++)
//    {
//        mpFormOptionsInfo optInfo = formOptionsInfos[i];
//        if(optInfo.opType == type){

//            pt::ptree optionNode,nameNode,valueNode,descriptionNode;

//            nameNode.put_value<std::string>(optInfo.op_item_Key);
//            valueNode.put_value<std::string>(optInfo.op_item_value);
//            descriptionNode.put_value<std::string>(optInfo.op_item_description);

//            optionNode.add_child("name", nameNode);
//            optionNode.add_child("value", valueNode);
//            optionNode.add_child("description", descriptionNode);

//            typeNode.add_child("option", optionNode);
//        }
//    }
//    tree.add_child("configuration." + type, typeNode);

//    auto settings = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
//    pt::write_xml(optConifg, tree, std::locale(), settings);

//    result = true;

}



void objectMapperToFormString(const FishInfo& fish,
                              std::string & string){

    //提交的表单数据会转换为键值对并按照 key1=val1&key2=val2 的方式进行编码，key 和 val 都进行了 URL 转码
    std::string tmp;
    tmp.append("Id=");
    tmp.append(std::to_string(fish.Id));
    tmp.append("&Name=");
    tmp.append(fish.Name);
    tmp.append("&Pinyin=");
    tmp.append(fish.Pinyin);
    tmp.append("&Describe=");
    tmp.append(fish.Describe);

    if(fish.IsLivingInSea){
        tmp.append("&IsLivingInSea=true");
    }
    else{
        tmp.append("&IsLivingInSea=false");
    }

    MP::CodecUtils::utf8Url_encode(string,tmp);
//    fish_post.Id = 3307;
//    fish_post.Name = "金枪鱼";
//    fish_post.Pinyin = "jinqiangyu";
//    fish_post.Describe = "金枪鱼是可将体温维持在比周围水体温度高的物种。它们是一些活跃而敏捷的食肉动物，拥有光滑的流线型身体，也是游动速度最快的远洋鱼类之一。金枪鱼可在温暖海域中发现，成为一种大量商业捕捞的鱼类，也是钓鱼活动当中的一种受欢迎鱼类。由于人类的过度捕捞，蓝鳍金枪鱼等部分金枪鱼物种已接近灭绝。";
//    fish_post.IsLivingInSea = true;
}

}   //Mapper
}   //MP

